package com.syh.jn.scm.domain.upstream.entity.finance;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.exception.IllegalParameterException;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import com.syh.core.ddd.domain.AbstractSimpleEntityObject;
import com.syh.jn.scm.domain.upstream.entity.sale.UpSaleOrder;
import com.syh.jn.scm.domain.upstream.entity.sale.UpSaleReturnOrder;
import com.syh.jn.scm.domain.upstream.repository.finance.UpCostBillReadRepository;
import com.syh.jn.scm.domain.upstream.repository.finance.UpCostBillRepository;
import com.syh.jn.scm.domain.upstream.repository.finance.UpIncomeBillReadRepository;
import com.syh.jn.scm.domain.upstream.repository.finance.UpIncomeBillRepository;
import com.syh.jn.scm.domain.upstream.repository.sale.UpSaleOrderReadRepository;
import com.syh.jn.scm.domain.upstream.repository.sale.UpSaleOrderRepository;
import com.syh.jn.scm.domain.upstream.repository.sale.UpSaleReturnOrderReadRepository;
import com.syh.jn.scm.dto.upstream.finance.UpStatementAccountBillMto.UpStatementAccountBillItemMto;
import com.syh.jn.scm.dto.upstream.finance.UpStatementAccountBillSto.UpStatementAccountBillItemSto;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.upstream.finance.enums.UpCostBillEnum;
import com.syh.jn.scm.service.api.upstream.finance.enums.UpIncomeBillEnum;
import com.syh.jn.scm.service.api.upstream.finance.enums.UpStatementAccountBillEnum;
import com.syh.jn.scm.service.api.upstream.sale.enums.UpSaleOrderEnums;
import com.syh.jn.scm.service.api.upstream.sale.enums.UpSaleReturnOrderEnums;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.UUID;

/**
 * 账单项
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class UpStatementAccountBillItem extends AbstractSimpleEntityObject<Long> {

  /**
   * 生成对账单项 每张单的数据逻辑校验分配给每个项在创建的时候自己去匹配 达到职责分离
   *
   * @param sto
   * @param customerId
   */
  UpStatementAccountBillItem(UpStatementAccountBillItemSto sto, Long customerId) {
    ValidationUtils.validate(sto);
    ExtBeanUtils.copyProperties(sto, this);
    this.setUuid(UUID.randomUUID().toString());
    this.createdItemTotalAmount(customerId, false);
  }

  /**
   * 生成对账单项 每张单的数据逻辑校验分配给每个项在创建的时候自己去匹配 达到职责分离
   *
   * @param mto
   * @param customerId
   */
  UpStatementAccountBillItem(UpStatementAccountBillItemMto mto, Long customerId) {
    ValidationUtils.validate(mto);
    ExtBeanUtils.copyProperties(mto, this);
    this.setUuid(UUID.randomUUID().toString());
    this.createdItemTotalAmount(customerId, true);
  }

  private void createdItemTotalAmount(Long customerId, boolean isUpdata) {
    switch (this.sourceType.intValue()) {
      case 2:
        UpSaleOrder saleOrder = this.getSaleOrd(customerId, isUpdata);
        this.totalAmount = saleOrder.getTotalInAmount();
        break;
      case 3:
        UpSaleReturnOrder saleReturnOrd = this.getSaleReturnOrd(customerId, isUpdata);
        this.totalAmount = saleReturnOrd.getReturnTotalOutAmount();
        break;
      case 4:
        UpIncomeBill incomeBill = this.getIncomeBill(customerId, isUpdata);
        this.totalAmount = incomeBill.getPrice();
        break;
      case 5:
        UpCostBill costBill = this.getCostBill(customerId, isUpdata);
        this.totalAmount = costBill.getPrice();
        break;
    }

    // 出现为空的情况只有单据类型与客户类型没对上 或者原始单据金额就发生错误了
    if (this.totalAmount == null) {
      throw new IllegalParameterException("非法参数，可能传入与供应商对账有销售单数据");
    }
  }

  /**
   * 处理销售订单
   *
   * @param customerId
   * @param isUpdata
   * @return
   */
  private UpSaleOrder getSaleOrd(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == UpStatementAccountBillEnum.SOURCE_SALE_ORD.getStatus(), "类型错误");
    UpSaleOrderReadRepository saleOrderReadRepository = (UpSaleOrderReadRepository) SpringContextUtils.getBean(UpSaleOrderRepository.class);
    UpSaleOrder saleOrder = saleOrderReadRepository.getById(this.sourceId);

    ExtAssert.isTrue(saleOrder.getUpStreamCompanyId().equals(customerId), saleOrder.getCode() + "，单据归属错误！");
    if (isUpdata) {
      if (saleOrder.getOrdState() != UpSaleOrderEnums.State.CONFIRM.getStatus()
              && saleOrder.getOrdState() != UpSaleOrderEnums.State.STATEMENT.getStatus()) {
        throw new BusinessException(saleOrder.getCode() + "，单据未在确认状态或未生成对账单");
      }
    } else {
      if (saleOrder.getOrdState() != UpSaleOrderEnums.State.CONFIRM.getStatus()) {
        throw new BusinessException(saleOrder.getCode() + "，单据未在确认状态！");
      }
      if (saleOrder.getStatementId() != null) {
        throw new BusinessException(saleOrder.getCode() + "，单据已经生成对账单！");
      }
    }

    if (!saleOrder.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    return saleOrder;
  }

  /**
   * 处理销售退货订单
   *
   * @param customerId
   * @param isUpdata
   * @return
   */
  private UpSaleReturnOrder getSaleReturnOrd(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == UpStatementAccountBillEnum.SOURCE_SALE_RETURN_ORD.getStatus(), "类型错误");
    UpSaleReturnOrderReadRepository saleReturnOrderReadRepository = (UpSaleReturnOrderReadRepository) SpringContextUtils.getBean(UpSaleReturnOrderReadRepository.class);
    UpSaleReturnOrder saleReturnOrder = saleReturnOrderReadRepository.getById(this.sourceId);
    ExtAssert.isTrue(saleReturnOrder.getUpStreamCompanyId().equals(customerId), saleReturnOrder.getReturnCode() + "，单据归属错误！");

    if (isUpdata) {
      if (saleReturnOrder.getReturnOrdState() != UpSaleReturnOrderEnums.State.CONFIRM.getStatus()
              && saleReturnOrder.getReturnOrdState() != UpSaleReturnOrderEnums.State.STATEMENT.getStatus()) {
        throw new BusinessException(saleReturnOrder.getReturnCode() + "，单据未在确认状态或未生成对账单！");
      }
    } else {
      if (saleReturnOrder.getReturnOrdState() != UpSaleReturnOrderEnums.State.CONFIRM.getStatus()) {
        throw new BusinessException(saleReturnOrder.getReturnCode() + "，单据未在确认状态！");
      }
      if (saleReturnOrder.getStatementId() != null) {
        throw new BusinessException(saleReturnOrder.getReturnCode() + "，单据已经生成对账单！");
      }
    }

    if (!saleReturnOrder.getReturnCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }

    return saleReturnOrder;
  }

  /**
   * 处理费用单
   *
   * @param customerId
   * @param isUpdata
   * @return
   */
  private UpCostBill getCostBill(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == UpStatementAccountBillEnum.SOURCE_COST_BILL.getStatus(), "类型错误");
    UpCostBillReadRepository costBillReadRepository = (UpCostBillReadRepository) SpringContextUtils.getBean(UpCostBillRepository.class);
    UpCostBill costBill = costBillReadRepository.getById(this.sourceId);

    ExtAssert.isTrue(costBill.getCustomerId().equals(customerId), costBill.getCode() + "，单据归属错误！");

    if (isUpdata) {
      if (costBill.getState() != UpCostBillEnum.CONFIRM.getStatus()
              && costBill.getState() != UpCostBillEnum.STATEMENT.getStatus()) {
        throw new BusinessException(costBill.getCode() + "，单据未在确认状态或未生成对账单！");
      }
    } else {
      if (costBill.getState() != UpCostBillEnum.CONFIRM.getStatus()) {
        throw new BusinessException(costBill.getCode() + "，单据未在确认状态！");
      }
      if (costBill.getStatementOfAccountId() != null) {
        throw new BusinessException(costBill.getCode() + "，单据已经生成对账单！");
      }
    }

    if (!costBill.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    if (costBill.getConfirmState().intValue() != UpCostBillEnum.OTHERPARTY_CONFIRM.getStatus()) {
      throw new BusinessException(costBill.getCode() + "，费用单未确认有效");
    }
    return costBill;
  }

  /**
   * 处理收入单
   *
   * @param customerId
   * @param isUpdata
   * @return
   */
  private UpIncomeBill getIncomeBill(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == UpStatementAccountBillEnum.SOURCE_INCOME_BILL.getStatus(), "类型错误");
    UpIncomeBillReadRepository incomeBillReadRepository = (UpIncomeBillReadRepository) SpringContextUtils.getBean(UpIncomeBillRepository.class);
    UpIncomeBill incomeBill = incomeBillReadRepository.getById(this.sourceId);

    ExtAssert.isTrue(incomeBill.getCustomerId().equals(customerId), incomeBill.getCode() + "，单据归属错误！");

    if (isUpdata) {
      if (incomeBill.getState() != UpIncomeBillEnum.CONFIRM.getStatus()
              && incomeBill.getState() != UpIncomeBillEnum.STATEMENT.getStatus()) {
        throw new BusinessException(incomeBill.getCode() + "，单据未在确认状态或未生成对账单！");
      }
    } else {
      if (incomeBill.getState() != UpIncomeBillEnum.CONFIRM.getStatus()) {
        throw new BusinessException(incomeBill.getCode() + "，单据未在确认状态！");
      }
      if (incomeBill.getStatementOfAccountId() != null) {
        throw new BusinessException(incomeBill.getCode() + "，单据已经生成对账单！");
      }
    }

    if (!incomeBill.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    if (incomeBill.getConfirmState() != UpIncomeBillEnum.OTHERPARTY_CONFIRM.getStatus()) {
      throw new BusinessException(incomeBill.getCode() + "，费用单未确认有效");
    }
    return incomeBill;
  }

  /**
   * 对账单id
   */
  private Long statementAccountBillId;
  /**
   * 来源单类型  2上游销售单(采购单) 3 上游销售退货单(采购退货单) 4 费用单 5 收入单
   */
  private Short sourceType;
  /**
   * 来源单号
   */
  private String sourceCode;
  /**
   * 来源单id
   */
  private Long sourceId;
  /**
   * 单据总额
   */
  private BigDecimal totalAmount;
}
